package user

import (
	"context"
	"encoding/json"
	"errors"
	"feng-che.com/server/driver-quiz/internal/cache"
	"feng-che.com/server/driver-quiz/internal/dep_jwt"
	"feng-che.com/server/driver-quiz/internal/sysLogger"
	serverCommon "fiberCommonUtils/common"
	"fiberCommonUtils/request"
	"fmt"
	"github.com/gofiber/fiber/v2"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"mongoDB"
	"strings"
	"time"
)

type uploadUserLogin struct {
	Name   string             `json:"name" validate:"required"`
	P      string             `json:"p" validate:"required"`
	UserID primitive.ObjectID `json:"userId"`
}

// ResponseUserLogin 为了安全，去掉多余信息
type ResponseUserLogin struct {
	Token       string `json:"token"`
	Information struct {
		UserName      string `json:"userName"`
		UserID        string `json:"userId"`
		UserLoginName string `json:"userLoginName"`
	} `json:"information"`
}

// AdminLogin 具有管理元权限的用户登录
func AdminLogin(c *fiber.Ctx) error {
	_user := c.Locals("user").(*User)
	data := request.ParsePostLikeRequest(c, &uploadUserLogin{}).(*uploadUserLogin)
	correct, err := _user.IsPasswordCorrect(&data.P)
	if err != nil {
		return fiber.NewError(500, fmt.Sprint("错误,", err.Error()))
	}
	if !correct {
		return fiber.NewError(400, "密码错误")
	}
	/*登入成功，写缓存文件和返回token*/
	token, err := dep_jwt.GenerateTokenForUser(&_user.ID)
	if err != nil {
		return fiber.NewError(500, "生成登录token错误", err.Error())
	}
	resp := ResponseUserLogin{
		Information: struct {
			UserName      string `json:"userName"`
			UserID        string `json:"userId"`
			UserLoginName string `json:"userLoginName"`
		}{UserName: _user.Information.Name, UserID: _user.ID.Hex(), UserLoginName: _user.AuthInfo.LoginName},
		Token: token,
	}
	ctx, cancel := mongoDB.MongoDBTimeoutContext()
	defer cancel()
	_, err = _user.SaveLoginTmpFile(ctx)
	if err != nil {
		return fiber.NewError(500, "保留登录临时文件错误", err.Error())
	}
	go _user.UpdateLastLogin()
	return c.JSON(serverCommon.MakeSuccessJson(resp))
}

// RequiredUserLogin 中间件函数，用于验证用户登录状态
// 从上下文中获取用户ID并加载登录用户信息
// c.Locals("user").(*User)
func RequiredUserLogin(c *fiber.Ctx) error {
	ctx, cancel := mongoDB.MongoDBTimeoutContext()
	defer cancel()
	id := c.Locals("UserID").(*primitive.ObjectID)
	LoginUser, err := LoadLoginTmpFile(ctx, id)
	if err != nil {
		return fiber.NewError(500, "读取登录文件失败,尝试重新登录,"+err.Error())
	}
	c.Locals("user", LoginUser)
	return c.Next()
}

func (u *User) UpdateLastLogin() {
	_, err := u.Update(context.Background(), &bson.D{
		{"$set", bson.D{
			{"auth_info.last_login", time.Now()},
		}},
	})
	if err != nil {
		sysLogger.SysLog.WithField("userID", u.ID.Hex()).Warn("更新用户登录时间错误," + err.Error())
	}
}

// Logout 登出
func Logout(c *fiber.Ctx) error {
	//ctx, cancel := mongoDB.MongoDBTimeoutContext()
	//defer cancel()
	//data := request.ParsePostLikeRequest(c, &uploadUserLogin{}).(*uploadUserLogin)
	// TODO 没有做
	return c.JSON(serverCommon.MakeSuccessJson("done"))
}

//// 缓存登录数据

func (u *User) CacheKey() string {
	key := fmt.Sprint("login:user:", u.ID.Hex())
	return key
}

// ClearLogin 清除登录文件
func (u *User) ClearLogin(ctx context.Context) (int64, error) {
	return cache.RedisDelValue(ctx, u.CacheKey())
}

func (u *User) SaveLoginTmpFile(ctx context.Context) (string, error) {
	jsonByte, err := json.Marshal(u)
	if err != nil {
		return "", errors.New("登录写入缓存错误，" + err.Error())
	}
	return cache.RedisSetValue(ctx, u.CacheKey(), string(jsonByte), 12*time.Hour)
}

func LoadLoginTmpFile(ctx context.Context, id *primitive.ObjectID) (*User, error) {
	u := new(User)
	u.ID = *id
	result := cache.RedisGetValue(ctx, u.CacheKey())
	data, err := result.Bytes()
	if err != nil {
		return nil, errors.New("登录文件错误，请重新登录," + err.Error())
	}
	err = json.Unmarshal(data, u)
	if err != nil {
		return nil, errors.New("登录文件错误，请重新登录," + err.Error())
	}
	return u, nil
}

// 修改密码

func ChangePassword(c *fiber.Ctx) error {
	_user := c.Locals("user").(*User)
	ctx, cancel := mongoDB.MongoDBTimeoutContext()
	type T struct {
		OldPassword string `json:"oldPassword" validate:"required"`
		NewPassword string `json:"newPassword" validate:"required,min=4"`
	}
	data := request.ParsePostLikeRequestV2(c, &T{})
	data.NewPassword = strings.TrimSpace(data.NewPassword)
	err := _user.FindByID(ctx, _user.ID) // 读取数据库里的用户信息
	if err != nil {
		return fiber.NewError(400, fmt.Sprint("用户信息读取错误,", err.Error()))
	}
	if yes, err := _user.IsPasswordCorrect(&data.OldPassword); !yes || err != nil {
		str := fmt.Sprint("旧密码错误,")
		if err != nil {
			str += err.Error()
		}
		return fiber.NewError(400, str)
	}
	passwordFiled, err := _user.FieldPassword(&data.NewPassword)
	if err != nil {
		return fiber.NewError(500, fmt.Sprint("密码计算错误,", err.Error()))
	}
	_, err = _user.Update(ctx, &bson.D{
		{"$set", bson.D{passwordFiled}},
	})
	if err != nil {
		return fiber.NewError(500, fmt.Sprint("保存错误,", err.Error()))
	}
	defer func() {
		cancel()
		_, _ = _user.ClearLogin(ctx)
	}()
	return c.JSON(serverCommon.MakeSuccessJson("done"))
}
